package com.hh.jwtdemo.utils;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.SecureRandom;

/**
 * 文件加密解密工具类
 * 使用AES-GCM算法进行文件的加密和解密操作
 */
public class FileCryptoUtil {
    // 定义加密算法名称/AES-GCM模式/无需填充
    private static final String ALGORITHM = "AES/GCM/NoPadding";
    // GCM模式下推荐的初始化向量IV长度为12字节
    private static final int IV_LENGTH = 12;
    // GCM模式下的认证标签长度为128位
    private static final int TAG_LENGTH = 128;

    /**
     * 加密文件
     * 读取输入文件，使用AES-GCM算法加密后写入输出文件
     *
     * @param inputFile  待加密的输入文件
     * @param outputFile 加密后的输出文件
     * @param key        加密密钥
     * @throws Exception 如果加密过程中发生错误
     */
    public static void encryptFile(File inputFile, File outputFile, String key) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
        byte[] iv = generateIV();
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, new GCMParameterSpec(TAG_LENGTH, iv));

        try (FileInputStream in = new FileInputStream(inputFile);
             FileOutputStream out = new FileOutputStream(outputFile)) {

            out.write(iv); // 将IV写入文件头部

            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1) {
                byte[] output = cipher.update(buffer, 0, bytesRead);
                if (output != null) out.write(output);
            }
            byte[] finalBytes = cipher.doFinal();
            if (finalBytes != null) out.write(finalBytes);
        }
    }

    /**
     * 解密文件
     * 读取输入文件，使用AES-GCM算法解密后写入输出文件
     *
     * @param inputFile  待解密的输入文件
     * @param outputFile 解密后的输出文件
     * @param key        解密密钥
     * @throws Exception 如果解密过程中发生错误
     */
    public static void decryptFile(File inputFile, File outputFile, String key) throws Exception {
        try (FileInputStream in = new FileInputStream(inputFile);
             FileOutputStream out = new FileOutputStream(outputFile)) {

            byte[] iv = new byte[IV_LENGTH];
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
            in.read(iv); // 读取IV
            cipher.init(Cipher.DECRYPT_MODE, keySpec, new GCMParameterSpec(TAG_LENGTH, iv));

            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1) {
                byte[] output = cipher.update(buffer, 0, bytesRead);
                if (output != null) out.write(output);
            }
            byte[] finalBytes = cipher.doFinal();
            if (finalBytes != null) out.write(finalBytes);
        }
    }

    /**
     * 生成初始化向量IV
     * 用于AES-GCM加密模式，长度为IV_LENGTH字节
     *
     * @return 生成的IV字节数组
     */
    private static byte[] generateIV() {
        byte[] iv = new byte[IV_LENGTH];
        new SecureRandom().nextBytes(iv);
        return iv;
    }

    public static void main(String[] args) {
        String inFile   = "c:/testnas/a.txt";
        String outFile  = "c:/testnas/b.txt";
        String outFile2 = "c:/testnas/a2.txt";
        try {
            FileCryptoUtil.encryptFile(new File(inFile), new File(outFile), "1234567890123456");
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            FileCryptoUtil.decryptFile(new File(outFile), new File(outFile2), "1234567890123456");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
